/**
 * @license
 * Copyright Alibaba.com All Rights Reserved.
 *
 * Use of this source code is governed by an MIT-style license that can be
 * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE
 */

import {
  CdkConnectedOverlay,
  CdkOverlayOrigin,
  ConnectedOverlayPositionChange,
  ConnectionPositionPair
} from '@angular/cdk/overlay';
import {ChangeDetectorRef, EventEmitter, NgZone, Output, TemplateRef} from '@angular/core';
import {
  getPlacementName,
  isNotNil,
  DEFAULT_TOOLTIP_POSITIONS,
  NgClassInterface,
  NgStyleInterface,
  ApesNoAnimationDirective,
  ApesTSType
} from '@shared/apes/core';

import { ApesToolTipTrigger } from '../apes-tooltip.definitions';

/**
 * Tooltip component. Also the base component for legacy components.
 */
export abstract class ApesToolTipBaseComponent {
  apesTitle: ApesTSType | null = null;
  apesContent: ApesTSType | null = null;
  apesVisible: boolean;
  apesPlacement: string;
  apesOverlayClassName: string;
  apesOverlayStyle: NgStyleInterface;
  apesMouseEnterDelay: number;
  apesMouseLeaveDelay: number;
  apesTrigger: ApesToolTipTrigger;
  apesTitleTemplate: TemplateRef<void>;
  apesContentTemplate: TemplateRef<void>;

  @Output() readonly apesVisibleChange = new EventEmitter<boolean>();

  overlay: CdkConnectedOverlay;
  origin: CdkOverlayOrigin;

  _classMap: NgClassInterface = {};
  _hasBackdrop = false;
  _prefix = 'apes-tooltip-placement';
  _visible = false;
  _positions: ConnectionPositionPair[] = [...DEFAULT_TOOLTIP_POSITIONS];
  _placement = 'top';
  _trigger: ApesToolTipTrigger = 'hover';


  get content(): string | TemplateRef<void> | null {
    return this.apesContent !== undefined ? this.apesContent : this.apesContentTemplate;
  }

  get title(): string | TemplateRef<void> | null {
    return this.apesTitle !== undefined ? this.apesTitle : this.apesTitleTemplate;
  }

  constructor(public cdr: ChangeDetectorRef, public noAnimation?: ApesNoAnimationDirective) {}

  show(): void {
    if (this.apesVisible) {
      return;
    }

    if (!this.isTitleEmpty() || !this.isContentEmpty()) {
      this.apesVisible = true;
      this.apesVisibleChange.emit(true);
      this.cdr.detectChanges();
    }
  }

  hide(): void {
    if (!this.apesVisible) {
      return;
    }

    this.apesVisible = false;
    this.apesVisibleChange.emit(false);
    this.cdr.detectChanges();
  }

  updateByDirective(): void {
    this.setClassMap();
    this.cdr.detectChanges();

    Promise.resolve().then(() => {
      this.updatePosition();
    });
  }

  /**
   * Force the component to update its position.
   */
  updatePosition(): void {
    if (this.origin && this.overlay && this.overlay.overlayRef) {
      this.overlay.overlayRef.updatePosition();
    }
  }

  onPositionChange(position: ConnectedOverlayPositionChange): void {
    this._placement = getPlacementName(position)!;
    this.setClassMap();
    this.cdr.detectChanges();
  }

  setClassMap(): void {
    this._classMap = {
      [this.apesOverlayClassName]: true,
      [`${this._prefix}-${this._placement}`]: true
    };
  }

  setOverlayOrigin(origin: CdkOverlayOrigin): void {
    this.origin = origin;
    this.cdr.markForCheck();
  }

  private isTitleEmpty(): boolean {
    return this.title instanceof TemplateRef ? false : this.title === '' || !isNotNil(this.title);
  }

  private isContentEmpty(): boolean {
    return this.content instanceof TemplateRef ? false : this.content === '' || !isNotNil(this.content);
  }
}
